# -*- coding: utf-8 -*-
"""
@Time： 2023/12/20 16:20
@Auth： gubei
@File：views.py
@IDE：PyCharm
@Description：身份认证相关视图
"""

from datetime import timedelta
import time

from fastapi import APIRouter, Depends, HTTPException, Request, Body
from fastapi.security import OAuth2PasswordRequestForm
from starlette import status
from jose import jwt, JWTError

from core.auth.oauth2 import authenticate_user, create_access_token, ACCESS_TOKEN_EXPIRE_MINUTES, SECRET_KEY, ALGORITHM, get_user_in_db
from core.decorators import log_action
from utils.response import R
from core.db.database import get_db
from core.models.models import Role

router = APIRouter()


@router.post("/token", summary='获取认证令牌', description='用户登录接口，返回JWT访问令牌')
@log_action('{form_data.username}登录了系统')
async def login_for_access_token(request: Request, form_data: OAuth2PasswordRequestForm = Depends()):
    """
    用户登录认证接口
    
    参数:
    - username: 用户名
    - password: 密码
    - scope: 权限范围(可选)
    
    返回:
    - access_token: JWT访问令牌
    - token_type: 令牌类型(bearer)
    """
    # 验证用户凭据
    user = authenticate_user(username=form_data.username, password=form_data.password)

    # 如果验证失败，返回401未授权错误
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED, 
            detail="用户名或密码错误",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 如果用户被禁用，返回错误
    if user.isActive == "0":
        return R.err(msg="用户已被禁用", code=status.HTTP_403_FORBIDDEN)
    
    # 创建访问令牌
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.userName, "scopes": form_data.scopes, "type": "access"},
        expires_delta=access_token_expires
    )
    
    # 创建刷新令牌（有效期更长）
    refresh_token_expires = timedelta(days=7)  # 刷新令牌有效期7天
    refresh_token = create_access_token(
        data={"sub": user.userName, "type": "refresh"},
        expires_delta=refresh_token_expires
    )

    # 获取角色名称
    db = next(get_db())
    role = db.query(Role).filter_by(id=user.role_id).first()
    role_name = role.name if role else None
    db.close()
    
    # 返回令牌
    return {
        "access_token": access_token, 
        "refresh_token": refresh_token,
        "token_type": "bearer",
        "expires_in": ACCESS_TOKEN_EXPIRE_MINUTES * 60,  # 过期时间（秒）
        "user_info": {
            "username": user.userName,
            "role": role_name,
            "nickname": user.nickName
        }
    }


@router.post("/refresh", summary='刷新访问令牌', description='使用刷新令牌获取新的访问令牌')
async def refresh_token(refresh_token: str = Body(..., embed=True)):
    """
    刷新访问令牌接口
    
    参数:
    - refresh_token: 刷新令牌
    
    返回:
    - access_token: 新的JWT访问令牌
    - token_type: 令牌类型(bearer)
    """
    try:
        # 验证刷新令牌
        payload = jwt.decode(
            refresh_token, SECRET_KEY, algorithms=[ALGORITHM]
        )
        username: str = payload.get("sub")
        token_type: str = payload.get("type")
        
        # 检查是否是刷新令牌
        if token_type != "refresh":
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="无效的刷新令牌",
                headers={"WWW-Authenticate": "Bearer"},
            )
        
        # 检查用户是否存在
        user = get_user_in_db(username=username)
        if user is None:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户不存在",
                headers={"WWW-Authenticate": "Bearer"},
            )
            
        # 检查用户是否被禁用
        if user.isActive == "0":
            return R.err(msg="用户已被禁用", code=status.HTTP_403_FORBIDDEN)
        
        # 创建新的访问令牌
        access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
        access_token = create_access_token(
            data={"sub": user.userName, "type": "access"},
            expires_delta=access_token_expires
        )
        
        return {
            "access_token": access_token,
            "token_type": "bearer",
            "expires_in": ACCESS_TOKEN_EXPIRE_MINUTES * 60  # 过期时间（秒）
        }
        
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的刷新令牌",
            headers={"WWW-Authenticate": "Bearer"},
        )
